package cn.xumaoyang.user.service.impl;

import cn.xumaoyang.basic.exception.BusinessException;
import cn.xumaoyang.basic.util.StrUtils;
import cn.xumaoyang.basic.util.UserConstants;
import cn.xumaoyang.user.domain.User;
import cn.xumaoyang.user.mapper.UserMapper;
import cn.xumaoyang.user.service.IVerifycodeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class VerifycodeServiceImpl implements IVerifycodeService {


    //需要用到User表，因为User里才是我们存参数的地方。
    @Autowired
    private UserMapper userMapper;

    //注入了redis的依赖之后注入这个可以使用redis。
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public void sendSmsCode(Map<String, String> params) {
        //首先获取到phone也就是电话号码,因为是map需要这样接收。
        String phone = params.get("phone");
        String type = params.get("type");  //register 注册   binder 绑定。
        //获取到之后进行判断电话号码是否为空。
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(type)){
            //这里为空踢到前端去告知用户。
            throw  new BusinessException("电话号码不能为空请重新输入");
        }
        String businessKey = "";
        //验证注册码
        if (type.equals("register")){
            //如果不为空则传递到数据库里进行比较。
            User user = userMapper.loadByPhone(phone);
            //进入数据库进行判断如果在数据库存在那就是不等于null,那就该给前端报错，电话号码已经被注册。
            if (user != null){
                throw  new BusinessException("该号码已经被注册，请输入密码登录");
            }
            businessKey = UserConstants.BUSINESS_TYPE_REGISTER + phone;

        }else if (type.equals("binder")){  //微信绑定验证码。
            businessKey = UserConstants.BUSINESS_TYPE_BINDER + phone;
        }
        sendCode(businessKey);
    }
    public void sendCode(String businessKey){
        //根据key获取到值，phone为key。
        Object codeObj  = redisTemplate.opsForValue().get(businessKey);

        //定义验证码变量。
        String code = "";

        //判断电话号码是否还存在。
        if (codeObj != null){//不等于null则表示存在没有过期。

            //转为String类型。
            String codeStr   = (String) codeObj;
            //判断是否过期,split是分割，[]是获取哪一些。
            // 比如说我们验证码8848加上时间戳之后就是8848:161616112316,
            // 根据：分割的话8848是下标0，161616112316是下标1
            String time  = codeStr.split(":")[1]; //获取到了发送验证码的时间戳了。

            //判断是否过期,System.currentTimeMillis()获取当前时间，Long.valueOf(time)把上面获取到时间戳转为Long类型，
            //当前时间减去已经发送的时间，获取到还剩余时间。
            long l = System.currentTimeMillis() - Long.valueOf(time);
            //判断是否过去了一分钟，因为在发送第一次验证码之后过去一分钟才能再次申请发送验证码。
            //1*60*1000是为一分钟，毫秒时间。
            if (l <= 1*60*1000){
                //没有超过一分钟则踢出错误。
                throw new BusinessException("请稍后再重新申请发送验证码");
            }
            //如果超过了，则应该重新发送验证码，是根据上一个验证码刷新时间这样来操作。
            //获取到验证码不获取时间戳。
            // 比如说我们验证码8848加上时间戳之后就是8848:161616112316,
            // 根据：分割的话8848是下标0，161616112316是下标1，获取到了8848
            code  = codeStr.split(":")[0];
        }else {
            //如果过期了，则该重新生成验证码,使用工具类设置长度为4.
            code = StrUtils.getComplexRandomString(4);
        }
        //并且保存新的验证码。
        redisTemplate.opsForValue().set(
                //重新设置电话号码。
                businessKey,
                //重新设置验证码,并且赋予时间戳。
                code+":"+System.currentTimeMillis(),
                //时间设置为3.
                3,
                //计时为分钟。
                TimeUnit.MINUTES
        );
        //发送给前端或者是接口的短信。
        System.out.println("您的验证码为"+code+"请在三分钟之内使用");
    }
}
